package common.framework.dsb.main;

import java.io.File;
import java.io.FileInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import javax.xml.bind.JAXBElement;

import common.framework.dsb.ResourceManager;
import common.framework.dsb.annotation.DSBCmd;
import common.framework.dsb.annotation.DSBService;
import common.framework.dsb.cmd.CmdAnnotationAware;
import common.framework.dsb.config.DSBConfType;
import common.framework.dsb.config.DisabledServiesType;
import common.framework.dsb.config.StartupServiesType;
import common.framework.dsb.config.SystemPropsType;
import common.framework.dsb.orm.MybatisSqlSessionProvider;
import common.framework.dsb.orm.SqlSessionProvider;
import common.framework.dsb.proxy.DefaultServiceProxy;
import common.framework.dsb.proxy.DefaultUploadHandler;
import common.framework.dsb.proxy.ServiceClassLoader;
import common.framework.dsb.proxy.ServiceProxy;
import common.framework.dsb.proxy.UploadHandler;
import common.framework.dsb.scanner.AnnotationAware;
import common.framework.dsb.scanner.AnnotationScanner;
import common.framework.dsb.scanner.DefaultAnnotationScanner;
import common.framework.dsb.server.DSBServer;
import common.framework.dsb.server.RMIDSBServer;
import common.framework.dsb.service.DefaultServiceConfig;
import common.framework.dsb.service.ServiceConfig;
import common.framework.jaxb.JAXBTool;
import common.framework.log.Logger;

public class Main {

	public final static String SCHEMAED_PACKAGE_NAME = "common.framework.dsb.config";

	public static DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");

	private static int[] format = { 30, 30 };

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {

		// DSB configuration
		String configFlie = "config" + File.separator + "dsb-config.xml";
		// mybatis configuration
		String ormConfigFlie = "config" + File.separator + "mybatis-config.xml";

		DSBConfType dsbConfType = loadDSBConfig(configFlie);

		int len = 100;

		// DSB configuration parameters
		String dsbServerName = dsbConfType.getDsbServerName();
		printinfo("dsb.server.name: " + dsbServerName, len);
		String logDir = dsbConfType.getDsbServerLogDir();
		printinfo("dsb.server.log.dir: " + logDir, len);
		String logName = dsbConfType.getDsbServerLogName();
		printinfo("dsb.server.log.name: " + logName, len);
		int logLevel = dsbConfType.getDsbServerLogLevel();
		printinfo("dsb.server.log.level: " + logLevel, len);
		long logMaxFileSize = dsbConfType.getDsbServerLogMaxfilesize();
		if (logMaxFileSize <= 0) {
			logMaxFileSize = 2;
		}
		printinfo("dsb.server.log.maxfilesize: " + logMaxFileSize + "M Bytes", len);
		// Logger initialize
		Logger.initialize(logDir, logName, logLevel, logMaxFileSize * 1024 * 1000);
		// server port
		int serverPort = dsbConfType.getDsbSocketPort();
		Logger.log(Logger.FUNCTION_LEVEL, "dsb.socket.port=" + serverPort);
		printinfo("dsb.socket.port: " + serverPort, len);
		// RMI port
		int rmiPort = dsbConfType.getDsbRmiServerPort();
		Logger.log(Logger.FUNCTION_LEVEL, "dsb.rmi.server.port=" + rmiPort);
		printinfo("dsb.rmi.server.port: " + rmiPort, len);
		// service deploy directory
		String serviceDir = dsbConfType.getDsbDeployDir();
		Logger.log(Logger.FUNCTION_LEVEL, "dsb.deploy.dir=" + serviceDir);
		printinfo("dsb.deploy.dir: " + serviceDir, len);
		// annotation scanning bypass directory
		String bypassDir = dsbConfType.getDsbAnnotationBypassDir();
		Logger.log(Logger.FUNCTION_LEVEL, "dsb.annotation.bypass.dir=" + bypassDir);
		printinfo("dsb.annotation.bypass.dir: " + bypassDir, len);
		// Server default language
		String language = dsbConfType.getDsbServerLanguage();
		Logger.log(Logger.FUNCTION_LEVEL, "dsb.server.language=" + language);
		printinfo("dsb.server.language: " + language, len);
		int cmdServerPort = dsbConfType.getCmdServerPort();
		Logger.log(Logger.FUNCTION_LEVEL, "cmd.server.port=" + cmdServerPort);
		printinfo("cmd.server.port: " + cmdServerPort, len);
		int cmdThreadCount = dsbConfType.getCmdThreadCount();
		Logger.log(Logger.FUNCTION_LEVEL, "cmd.thread.count=" + cmdThreadCount);
		printinfo("cmd.thread.count: " + cmdThreadCount, len);
		long cmdTimeout = dsbConfType.getCmdConnTimeout();
		Logger.log(Logger.FUNCTION_LEVEL, "cmd.conn.timeout=" + cmdTimeout);
		printinfo("cmd.conn.timeout: " + cmdTimeout, len);

		// startup services
		List<String> startupServices = new ArrayList<String>();
		StartupServiesType startupServiesType = dsbConfType.getStartupservices();
		if (startupServiesType != null) {
			int num = 0;
			for (String service : startupServiesType.getService()) {
				if (null != service && !"".equalsIgnoreCase(service.trim())) {
					num++;
					startupServices.add(service);
					Logger.log(Logger.FUNCTION_LEVEL, service);
					printinfo("startup service: " + service, len);
				}
			}
		}

		// disabled services
		List<String> disabledServies = new ArrayList<String>();
		DisabledServiesType disabledServiesType = dsbConfType.getDisabledservices();
		if (disabledServiesType != null) {
			int num = 0;
			for (String service : disabledServiesType.getService()) {
				if (null != service && !"".equalsIgnoreCase(service.trim())) {
					num++;
					disabledServies.add(service);
					Logger.log(Logger.FUNCTION_LEVEL, service);
					printinfo("disable service: " + service, len);
				}
			}
		}

		// configured system properties
		List<SystemPropsType> spts = dsbConfType.getSystemprops();
		Logger.log(Logger.FUNCTION_LEVEL, "load system properties=" + spts.size());
		for (SystemPropsType spt : spts) {
			System.setProperty(spt.getPropName(), spt.getPropValue());
			Logger.log(Logger.FUNCTION_LEVEL, spt.getPropName() + "=" + spt.getPropValue());
			printinfo("system property: " + spt.getPropName() + "=" + spt.getPropValue(), len);
		}
		printinfo(null, len);

		
		ResourceManager.locale = new Locale(language);
		// DSB kernel boot-strap classloader (dsb-x.x)
		ClassLoader currentClassLoader = Main.class.getClassLoader();
		// DSB service classloader (to load all jars in deploy-DIR)
		ServiceClassLoader newClassLoader = new ServiceClassLoader(ServiceClassLoader.EMPTY_URL_ARRAY, currentClassLoader);
		File deployables = new File(serviceDir);
		System.out.println(new Date() + " DSB deploy dir:" + deployables.getAbsolutePath());
		newClassLoader.loadLibrary(deployables);
		Thread.currentThread().setContextClassLoader(newClassLoader);

		// class annotation scanning
		final AnnotationScanner scanner = new DefaultAnnotationScanner(serviceDir, bypassDir);
		scanner.addAnnotationClass(DSBService.class);
		scanner.addAnnotationClass(DSBCmd.class);
		final ServiceConfig serviceConfig = new DefaultServiceConfig(ResourceManager.locale, serviceDir);
		final CmdAnnotationAware cmdAnnotationAware = new CmdAnnotationAware(cmdServerPort, cmdThreadCount, cmdTimeout);
		final SqlSessionProvider sqlSessionProvider = new MybatisSqlSessionProvider();
		final ServiceProxy serviceProxy = new DefaultServiceProxy(serviceConfig, sqlSessionProvider);
		final UploadHandler uploadHandler = new DefaultUploadHandler(serviceProxy, serviceConfig);
		final DSBServer dsbServer = new RMIDSBServer(serverPort, rmiPort, serviceProxy);
		scanner.register((AnnotationAware) serviceConfig);
		scanner.register(cmdAnnotationAware);
		// system start
		try {
			System.out.println(new Date() + " DSB micro-kernel is starting.");
			Logger.log(Logger.FUNCTION_LEVEL, "DSB micro-kernel is starting.");

			// class scanner
			scanner.start();
			// command server start
			cmdAnnotationAware.start();
			// ORM
			sqlSessionProvider.start(ormConfigFlie);
			// ServiceProxy to start all service
			System.out.println(new Date() + " DSB micro-kernel begin check all services.");
			serviceProxy.start(startupServices, disabledServies);
			System.out.println(new Date() + " DSB micro-kernel finished check all services.");
			// DSBServer
			dsbServer.start();
			Logger.log(Logger.FUNCTION_LEVEL, " DSB micro-kernel started.");
			System.out.println(new Date() + " DSB micro-kernel started.");
		} catch (Throwable e) {
			e.printStackTrace(System.out);
			Logger.printStackTrace(Logger.FATAL_LEVEL, "Fatal error while server startup", e);
			Logger.shutDown();
			System.exit(0);
		}

		// System shutdown
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				try {
					dsbServer.close();
					uploadHandler.close();
					serviceProxy.close();
					serviceConfig.close();
					cmdAnnotationAware.close();
				} catch (Exception e) {
				} finally {
					Logger.shutDown();
				}
			}
		});
	}

	private static DSBConfType loadDSBConfig(String configFlie) throws Exception {
		DSBConfType dsbConfType = null;
		try {
			FileInputStream fin = new FileInputStream(configFlie);
			JAXBElement<DSBConfType> jaxbElement = (JAXBElement<DSBConfType>) JAXBTool.unmarshal(fin, SCHEMAED_PACKAGE_NAME, Main.class.getClassLoader());
			dsbConfType = jaxbElement.getValue();
			fin.close();
		} catch (Exception e) {
			e.printStackTrace(System.out);
			System.err.println("Failed to load config file:" + configFlie);
			System.exit(0);
		}
		return dsbConfType;
	}

	private static void printinfo(String info, int length) {
		if (info == null) {
			StringBuffer sb = new StringBuffer("");
			for (int i = 0; i < length; i++) {
				sb.append("*");
			}
			System.out.println(sb.toString());
		} else {
			StringBuffer sb = new StringBuffer("*");
			sb.append(" ");
			sb.append(info);
			int pad = length - info.length() - 3;
			for (int i = 0; i < pad; i++) {
				sb.append(" ");
			}
			sb.append("*");
			System.out.println(sb.toString());

		}
	}// printinfo

}
